/*
 * By: Werner Schuster (murphee)
 * 
 * Copyright (c) 2005-2006 Werner Schuster (murphee)
 * 
 * This file is part of the EclipseShell project. EclipseShell is subject 
 * to the Eclipse Public License (EPL) available at
 * http://www.eclipse.org/org/documents/epl-v10.php
 * or in the file /epl-v10.html in the source for other info
 * see the /eclipseshell.license file
 */
package net.sf.eclipseshell.internal.extensions;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.eclipseshell.EclipseShellPlugin;
import net.sf.eclipseshell.extensions.DefaultExecutionProviderHandle;
import net.sf.eclipseshell.extensions.IExecutionEnvironmentProvider;
import net.sf.eclipseshell.extensions.IExecutionProviderHandle;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;

public class ExecutionProviderManager  {

	// TODO: maybe refactor this to go somewhere else
	static Map fileExtensionToProvider = new HashMap();
	static Map idToProvider = new HashMap();
	static Map idToHandle_ = new HashMap();
	// TODO: this package is exported (from the plugin) so this shouldn't be available !!
	public static  IExecutionEnvironmentProvider getProvider(String type){
		updateProviderMap();
		if(fileExtensionToProvider.keySet().size() > 0){
			return (IExecutionEnvironmentProvider)fileExtensionToProvider.get(type.trim());
		} else {
			return null;
		}
	}
	
	public static  IExecutionEnvironmentProvider getProviderById(String id){
		updateProviderMap();
		if(idToProvider.keySet().size() > 0){
			return (IExecutionEnvironmentProvider)idToProvider.get(id.trim());
		} else {
			return null;
		}
	}
	
	private static IExecutionEnvironmentProvider updateProviderMap() {
		IExtension[] exts = getExtensionProviders();
		IExecutionEnvironmentProvider prov = null;
		
		for (int i = 0; i < exts.length; i++) {
			IConfigurationElement[] elem = exts[i].getConfigurationElements();
			if(elem != null && elem.length > 0){
				String attrs[] = elem[0].getAttributeNames();
				try {
					Object tempProv = elem[0].createExecutableExtension("class");
					if (tempProv instanceof IExecutionEnvironmentProvider) {
						prov = (IExecutionEnvironmentProvider) tempProv;
					}
					// setup id -> provider mapping
					Object id = elem[0].getAttribute("id");
					if(id != null){
						idToProvider.put(id.toString().trim(), prov);
					}
					// setup file extension -> provider mapping 
					// TODO: refactor the splitting and handling into its own method
					Object tempExtension = elem[0].getAttribute("fileExtension");
					if (tempExtension instanceof String) {
						String[] extensions = splitCommaSeparatedExtensions(tempExtension);
						for (int j = 0; j < extensions.length; j++) {
							String currExtension = extensions[j];
							fileExtensionToProvider.put(currExtension.trim(), prov);
						}
						
					}

					Object tempSupportedRunModes = elem[0].getAttribute("supportedRunModes");
					if(tempSupportedRunModes == null){
						tempSupportedRunModes = "";
					}
					Object displayName = elem[0].getAttribute("displayName");
					if (displayName == null) {
						displayName = "[NoName: " + id.toString() + "]";
					}
					
					if(tempExtension!=null && tempExtension != null && id != null){
						idToHandle_.put(id, new DefaultExecutionProviderHandle(displayName.toString(), splitCommaSeparatedExtensions(tempExtension), splitCommaSeparatedExtensions(tempSupportedRunModes), id.toString()));
					}				
					
					
				} catch (Exception e) {
					EclipseShellPlugin.getDefault().log(Status.WARNING, e.getLocalizedMessage(), e);
				}
				
			}
			// end loading launchCommand extension data
		}
	
		return prov;
		
	}

	private static IExtension[] getExtensionProviders() {
		IExtensionRegistry reg = Platform.getExtensionRegistry();
		IExtensionPoint[] points = reg.getExtensionPoints(EclipseShellPlugin.ECLIPSE_SHELL_PLUGIN_ID);
		if(points != null){
			return points[0].getExtensions();
		}  
		return null;
	}

	/**
	 * 
	 * @param extension
	 * @return String[] with two elements with {delimiter, delimiterRegex} OR null if this extension is not defined.
	 */
	// TODO: add delimiter to provider handle!!!
	public static String[] getRegionDelimiterRegexForFileExtension(String extension) {
		IExtension[] exts = getExtensionProviders();
		if(exts != null){			
			
			for (int i = 0; i < exts.length; i++) {
				IConfigurationElement[] elem = exts[i].getConfigurationElements();
				if(elem != null && elem.length > 0){
					String attrs[] = elem[0].getAttributeNames();
					try {
						Object tempExtension = elem[0].getAttribute("fileExtension");
						if (tempExtension instanceof String) {
							String[] extensions = splitCommaSeparatedExtensions(tempExtension);
							boolean extensionFound = false;
							for (int j = 0; j < extensions.length; j++) {
								String currExtension = extensions[j];
								if(extension.equalsIgnoreCase(currExtension.trim())){
									extensionFound = true;
									break;
								}
							}
							if(extensionFound){
								Object delimiter = elem[0].getAttribute("delimiter");
								Object delimiterRegex = elem[0].getAttribute("delimiterRegex");
								if(delimiter != null && delimiterRegex != null){
									String delimiterString = delimiter.toString().replaceAll("\\\\n", "\n");
									String delimiterRegexString = delimiterRegex.toString().replaceAll("\\\\n", "\n");
									
									return new String[]{delimiterString, delimiterRegexString};				        	
								}
								
							}
						}
					} catch (Exception e) {
						EclipseShellPlugin.getDefault().log(Status.WARNING, e.getLocalizedMessage(), e);
					}
				}
			}
		}
		return null;
	}

	private static String[] splitCommaSeparatedExtensions(Object tempExtension) {
		String[] extensions = tempExtension.toString().split(",");
		return extensions;
	}

	// TODO: refactor extension querying code 
	public static IExecutionProviderHandle[] getAllProviders() {
		updateProviderMap();
		Collection values = idToHandle_.values();
		return (IExecutionProviderHandle[]) values.toArray(new IExecutionProviderHandle[values.size()]);		
	}

	/**
	 * Adds a new  IExecutionEnvironmentProvider to the provider list.
	 * 
	 * @param handle
	 * @param prov
	 */
	public static void addProvider(IExecutionProviderHandle handle, IExecutionEnvironmentProvider prov) {
		if(handle != null){
			String id = handle.getId();
			if(id != null){
				idToProvider.put(id.trim(), prov);
				idToHandle_.put(id.trim(), handle);
			}
			
			String[] fileExtensions = handle.getFileExtensions();
			if(fileExtensions != null){
				for (int i = 0; i < fileExtensions.length; i++) {
					String currExtension = fileExtensions[i];
					fileExtensionToProvider.put(currExtension.trim(), prov);					
				}
			}
		}
	}

}
